<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>B站抽奖监控</title>
        <style>
            body {
                font-family: Arial,sans-serif;
                max-width: 900px;
                margin: 30px auto;
                border: 2px solid #000;
                padding: 5px
            }

            #message {
                text-align: center;
                padding: 10px;
                margin: 0
            }

            #raffle-table {
                width: 100%;
                border-collapse: collapse;
                margin-top: 20px
            }

            #raffle-table th,#raffle-table td {
                border: 1px solid #000;
                padding: 8px;
                text-align: center
            }

            #raffle-table th {
                font-size: 1.1em;
                background-color: #959595
            }

            #raffle-table td {
                word-wrap: break-word
            }

            #raffle-table th:nth-child(-n+20),#raffle-table td:nth-child(-n+20) {
                width: 150px
            }

            #raffle-table th:nth-child(2),#raffle-table td:nth-child(2) {
                width: 250px
            }

            a {
                text-decoration: none;
                color: #000
            }

            #face {
                border-radius: 50%;
                overflow: hidden;
                border: 2px solid #000
            }

            #dropdown {
                font-size: .8em;
                background-color: #959595
            }

            #dropdown option {
                font-size: .8em
            }

            #inputBox,#ff,#xz,#dhh,#tbox1,#tbox3,#tbox6 {
                display: inline-block;
                font-size: .8em
            }

            #inputNumber, #ffV,#xzV,#dhhV {
                width: 3em;
                font-size: .8em;
                border: none;
                background-color: #959595;
                border-bottom: 2px solid #000;
                padding-bottom: 2px
            }
        </style>
    </head>
    <body>
        <h1 id="message">B站抽奖监控</h1>
        点击抽奖类型、奖品、天选限制可以进行筛选，点击主播头像或昵称可以跳转到直播间
        <table id="raffle-table">
            <thead>
                <tr>
                    <th>
                        <span class="text-button" onclick="clickt1()">
                            抽奖类型<span id="type-indicator"></span>
                        </span>
                        <div id="tbox1" style="display:none;">
                            <div>
                                <label>
                                    <input type="checkbox" value="天选时刻" onchange="clicktbox()" checked>天选时刻
                                </label>
                            </div>
                            <div>
                                <label>
                                    <input type="checkbox" value="人气红包" onchange="clicktbox()" checked>人气红包
                                </label>
                            </div>
                            <div>
                                <label>
                                    <input type="checkbox" value="节奏风暴" onchange="clicktbox()" checked>节奏风暴
                                </label>
                            </div>
                            <div>
                                <label>
                                    <input type="checkbox" value="电池红包" onchange="clicktbox()" checked>电池红包
                                </label>
                            </div>
                        </div>
                    </th>
                    <th>直播间</th>
                    <th>
                        <span class="text-button" onclick="clickt3()">
                            奖品<span id="prize-indicator"></span>
                        </span>
                        <br>
                        <span id="inputBox" style="display:none;">
                            人气红包≥<input type="number" id="inputNumber" value="0" min="0" step="0.1" placeholder="金额" onkeydown="clickt3_1(event)">
                        </span>
                        <div id="tbox3" style="display:none;">
                            <div>
                                <label>
                                    <input type="checkbox" value="实物天选" onchange="clicktbox()" checked>实物天选
                                </label>
                            </div>
                            <div>
                                <label>
                                    <input type="checkbox" value="礼物天选" onchange="clicktbox()" checked>礼物天选
                                </label>
                            </div>
                        </div>
                    </th>
                    <th>在线人数</th>
                    <th>剩余时间</th>
                    <th style="display:none;">抽奖编号</th>
                    <!-- <th>备注</th> -->
                    <th>
                        <span class="text-button" onclick="clickt6()">
                        天选限制<span id="t6"></span>
                        </span>
                        <br>
                        <!-- <span id="inputBox" style="display:none;">
                            人气红包≥<input type="number" id="inputNumber" min="0" step="0.1" placeholder="金额" onkeydown="clickt3_1(event)">
                        </span> -->
                        <div id="tbox6" style="display:none;">
                            <div>
                                <label>
                                    <input type="checkbox" value="0" onchange="clicktbox()" checked>无
                                </label>
                            </div>
                            <div>
                                <label>
                                    <input type="checkbox" value="1" onchange="clicktbox()" checked>关注
                                </label>
                            </div>
                            <div>
                                <label>
                                    <input type="checkbox" value="2" onchange="clicktbox()" checked>勋章
                                    <span id="xz">
                                        ≤<input type="number" id="xzV" min="1" max="20" step="1" placeholder="金额" value="20" onkeydown="clickt6_1(event)">
                                    </span>
                                </label>

                                
                            </div>
                            <div>
                                <label>
                                    <input type="checkbox" value="3" onchange="clicktbox()" checked>大航海
                                    <span id="dhh">
                                        ≤
                                        <select id="dhhV" onchange="clickt6_1(event)" style="width:5em;">
                                            <option value="1" selected>总督</option>
                                            <option value="2">提督</option>
                                            <option value="3">舰长</option>
                                        </select>
                                    </span>
                                </label>
                                
                            </div>
                            <div>
                                <label>
                                    <input type="checkbox" value="ff" onchange="clicktbox()" checked>付费
                                    <span id="ff">
                                        ≤<input type="number" id="ffV" min="0" step="0.1" placeholder="金额" value="99999" onkeydown="clickt6_1(event)" style="width:5em;">
                                    </span>
                                </label>
                            </div>
                        </div>

                    </th>
                    
                    <th>参与人数</th>
                </tr>
            </thead>
            <tbody></tbody>
        </table>
        <script>


var queryParams = new URLSearchParams(window.location.search)
    , keyValue = queryParams.get('key')
    , websocketUrl = keyValue ? `ws://${window.location.host}/ws?key=${keyValue}` : `ws://${window.location.host}/ws`;
let websocket, tableRows = {};
function connectWebSocket() {
    websocket = new WebSocket(websocketUrl);
    websocket.onopen = ()=>{
        print2Message('监控已连接')
    }
    ;
    websocket.onmessage = (event)=>{
        handleMessage(JSON.parse(event.data))
    }
    ;
    websocket.onclose = ()=>{
        print2Message('正在重连监控...');
        setTimeout(connectWebSocket, 5e3)
    }
    ;
}
let messageTimeout;
function print2Message(txt) {
    const messageElement = document.getElementById('message');
    messageElement.innerText = txt;
    if (messageTimeout) {
        clearTimeout(messageTimeout);
    }
    messageTimeout = setTimeout(()=>{
        messageElement.innerText = 'B站直播监控'
    }
    , 55e2);
}
function handleMessage(data) {
    //console.log(data);
    if (data.type === 'message') {
        print2Message(data.message);
    } else if (data.type === 'raffle') {
        //console.log(isShow(data.data));
        updateTable(data.data);
    } else if (data.type === 'refresh') {
        //console.log(isShow(data.data));
        //修改在线人数
        console.log(data.data);
        updateOnline(data.data)
    }
}
function updateOnline(newData) {
    let roomid = newData.room_id;
    let online =  newData.online;
    const rows = document.querySelectorAll('tbody tr');
    let have = false;
    for (const row of rows) {
        const data = JSON.parse(row.querySelector('td:nth-child(10)').innerText);
        const room_id = data.room_id;
        if (roomid === room_id) {
            // 获取要更新的表格单元格
            const statusCell = row.querySelector('td:nth-child(4)');
            if (statusCell.innerText==-1){
                statusCell.innerText = online;
            }
            // 使用正则表达式提取括号前面的数字
            const match = statusCell.innerText.match(/(\d+)/);
            
            if (match) {
                const currentOnline = parseInt(match[0], 10);
                console.log(statusCell.innerText,"匹配到:",currentOnline,"现在:",online);
                // 计算增减值
                const diff = online - currentOnline;
                
                // 更新表格单元格的文本，包含增减值
                statusCell.innerText = `${currentOnline} (${diff > 0 ? '+' : ''}${diff})`;
            } else {
                // 如果没有找到数字，直接显示 online
                statusCell.innerText = online;
            }
            have = true;
        }
        if (newData.raffle_id == data.raffle_id){
            // 获取要更新的表格单元格
            const statusCell = row.querySelector('td:nth-child(11)');
            statusCell.innerText = newData.attended;
            have = true;
        }
    }
    if (!have){
        console.log("不存在该房间！")
    }
}


const raffleTypeMapping = {
            ANCHOR: '天选时刻',
            POPULARITY_RED: '人气红包',
            STORM: '节奏风暴',
            RED: '电池红包',
        };
function updateTable(data) {
    const table = document.getElementById('raffle-table').getElementsByTagName('tbody')[0];
    if (tableRows[data.raffle_id]) {
        const row = tableRows[data.raffle_id];
        const currentTime = Math.floor(new Date().getTime() / 1e3);
        const endTime = row.cells[7].innerText;
        const remainingTime = endTime - currentTime;
        row.cells[4].innerText = formatTime(remainingTime);
        if (remainingTime <= 0) {
            delete tableRows[data.raffle_id];
            row.remove();
        }
    } else {
        const newRow = table.insertRow();
        const raffleType = raffleTypeMapping[data.raffle_type] || '未知类型';
        const roomLink = isMobileDevice() ? `bilibili://live/${data.room_id}` : `https://live.bilibili.com/${data.room_id}`;
        const currentTime = Math.floor(new Date().getTime() / 1e3);
        const endTime = data.start_time === 0 ? currentTime + data.time : data.start_time + data.time;
        let prize;
        let typeImg;
        let note = '';
        if (data.raffle_type === 'ANCHOR') {
            let requirement = '';
            if (data.require_type === 0) {
                requirement = '无';
            } else if (data.require_type === 1) {
                requirement = '关注';
            } else if (data.require_type === 2) {
                requirement = `勋章 ${data.require_value}级`;
            } else if (data.require_type === 3) {
                if (data.require_value === 1) {
                    requirement = '总督';
                } else if (data.require_value === 2) {
                    requirement = '提督';
                } else if (data.require_value === 3) {
                    requirement = '舰长';
                }
            } else {
                requirement = `${data.raffle_type}-${data.require_value}`;
            }
            note = `${requirement}`;
            if (data.gift_price !== 0) {
                if (note != '') {
                    note += ',';
                }
                note += `￥${data.gift_price / 1e3}`;
            }
            typeImg = 'https://i0.hdslb.com/bfs/live/b47453a0d42f30673b6d030159a96d07905d677a.webp';
            prize = `${data.award_name} x${data.award_num}`;
        } else if (data.raffle_type === 'POPULARITY_RED') {
            typeImg = 'https://message.biliimg.com/bfs/im/dd213d98e64f5fc288a95dd9af582c66146563374.png@80w_80h_1c.webp';
            prize = `￥${data.total_price / 1e3}`;
        } else if (data.raffle_type === 'STORM') {
            typeImg = 'http://static.hdslb.com/live-static/live-room/images/gift-section/mobilegift/2/jiezou.gif?2017011901';
            prize = '亿圆';
        } else if (data.raffle_type === 'RED') {
            typeImg = 'https://i0.hdslb.com/bfs/activity-plat/static/20210116/1d0c5a1b042efb59f46d4ba1286c6727/QPDhSONpxC.png';
            prize = '电池';
        } else {
            prize = '未知奖品';
        }
        newRow.innerHTML = `<td><img id="animatedWebp-${data.raffle_id}" style="height:1.4em;object-fit:contain;margin-bottom:-.2em;">${raffleType}</td><td><div style="display:flex;align-items:center;"><a href="${roomLink}" ${isMobileDevice() ? '' : 'target="_blank"'} style="display:flex;align-items:center;width:100%;"><div style="flex:0 0 50px;display:flex;justify-content:flex-start;align-items:center;"><meta name="referrer" content="no-referrer"><img id="face" src="${data.face}" alt="" style="width:50px;height:50px;"></div><div style="text-align:left;width:100%;"><div class="upper-text" style="text-align:center;width:100%;display:flex;justify-content:center;">${data.uname}</div><div class="lower-text" style="text-align:center;width:100%;display:flex;justify-content:center;font-size:.5em;">${data.official_desc ? data.official_desc : '&nbsp;'}</div></div></a></div></td><td>${prize}</td><td>${data.online}</td><td id="remaining-time-${data.raffle_id}">${formatTime(data.time)}</td><td style="display:none;">${data.raffle_id}</td><td>${note}</td><td style="display:none;">${endTime}</td><td style="display:none;">${data.award_type}</td><td style="display:none;">${JSON.stringify(data)}</td><td>${'-'}</td>`;
            const imgElement = document.getElementById(`animatedWebp-${data.raffle_id}`);

            fetch(typeImg)
            .then(response => response.blob())
            .then(blob => {
            const blobUrl = URL.createObjectURL(blob);
            imgElement.src = blobUrl;
            });

        const show = isShow(data);
        if (!show) {
            newRow.style.display = 'none';
        }
        if (table.firstChild) {
            table.insertBefore(newRow, table.firstChild);
        } else {
            table.appendChild(newRow);
        }
        tableRows[data.raffle_id] = newRow;
    }
}
function formatTime(seconds) {
    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
}
function isMobileDevice() {
    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
function updateRemainingTime() {
    for (const raffleId in tableRows) {
        const row = tableRows[raffleId];
        const currentTime = Math.floor(new Date().getTime() / 1e3);
        const endTime = row.cells[7].innerText;
        const remainingTime = endTime - currentTime;
        if (remainingTime > 0) {
            row.cells[4].innerText = formatTime(remainingTime - 1);
        } else {
            delete tableRows[raffleId];
            row.remove();
        }
    }
}
window.onload = function() {
    connectWebSocket();
    setInterval(updateRemainingTime, 1e3);
}
;
let checkboxContainerVisible = false;
function clickt1() {
    const container = document.getElementById('tbox1');
    if (checkboxContainerVisible) {
        container.style.display = 'none';
    } else {
        container.style.display = 'block';
    }
    checkboxContainerVisible = !checkboxContainerVisible;
}
function toggleCheckboxContainer2() {
    const container = document.getElementById('tbox3');
    if (checkboxContainerVisible) {
        container.style.display = 'none';
    } else {
        container.style.display = 'block';
    }
    checkboxContainerVisible = !checkboxContainerVisible;
}

function getCheckboxStatus(selector) {
    const checkboxes = document.querySelectorAll(selector);
    const selectedOptions = [];
    for (const checkbox of checkboxes) {
        if (checkbox.checked) {
            selectedOptions.push(checkbox.value);
        }
    }
    return selectedOptions;
}

function clicktbox() {
    const selectedOptions = getCheckboxStatus('#tbox1 input');
    const selectedOptions2 = getCheckboxStatus('#tbox3 input');
    const minPrize = getValueFromInputBox();
    const indicator = document.getElementById('type-indicator');
    if (!selectedOptions.includes('人气红包')) {
        hideInputBox();
    }
    if (!selectedOptions.includes('天选时刻')) {
        hideBox3();
        hideBox6();
    }
    const container = document.getElementById('tbox1');
    const checkboxes = container.querySelectorAll('input[type="checkbox"]');
    let allChecked = true;
    for (const checkbox of checkboxes) {
        if (!checkbox.checked) {
            allChecked = false;
            break;
        }
    }
    if (allChecked) {
        indicator.textContent = '';
    } else {
        indicator.textContent = '*';
    }
    clicktbox6();
    
    updatePrizeIndicator();
    const rows = document.querySelectorAll('tbody tr');
    for (const row of rows) {
        const data = JSON.parse(row.querySelector('td:nth-child(10)').innerText);
        const show = isShow(data);
        if (show) {
            row.style.display = 'table-row';
        } else {
            row.style.display = 'none';
        }
    }
}
function updatePrizeIndicator() {
    const indicator = document.getElementById('prize-indicator');
    const container2 = document.getElementById('tbox3');
    const checkboxes2 = container2.querySelectorAll('input[type="checkbox"]');
    let allChecked2 = true;
    for (const checkbox of checkboxes2) {
        if (!checkbox.checked) {
            allChecked2 = false;
            break;
        }
    }
    if (allChecked2 && getValueFromInputBox() === 0) {
        indicator.textContent = '';
    } else {
        indicator.textContent = '*';
    }
}
function toggleDropdown() {
    const container = document.getElementById('dropdown-container');
    if (dropdownVisible) {
        container.style.display = 'none';
    } else {
        showDropdown();
    }
    dropdownVisible = !dropdownVisible;
}
function showDropdown() {
    const container = document.getElementById('dropdown-container');
    const dropdown = document.getElementById('dropdown');
    const rows = document.querySelectorAll('tbody tr');
    const uniqueItems = new Set();
    for (const row of rows) {
        const data = JSON.parse(row.querySelector('td:nth-child(10)').innerText);
        const firstColumnValue =raffleTypeMapping[data.raffle_type] || '未知类型';
        uniqueItems.add(firstColumnValue);
    }
    dropdown.innerHTML = '';
    for (const item of uniqueItems) {
        const option = document.createElement('option');
        option.value = item;
        option.textContent = item;
        if (previousSelection.includes(item)) {
            option.selected = true;
        }
        dropdown.appendChild(option);
    }
    const rect = container.previousElementSibling.getBoundingClientRect();
    container.style.top = rect.bottom + 'px';
    container.style.left = rect.left + 'px';
    container.style.display = 'block';
}
function hideDropdown() {
    const container = document.getElementById('dropdown-container');
    container.style.display = 'none';
    dropdownVisible = false;
}
function clickt3() {
    toggleBox3();
    clicktbox();
}
function getValueFromInputBox() {
    const inputNumber = document.getElementById('inputNumber');
    const value = inputNumber.value.trim();
    if (value === '') {
        return 0;
    } else {
        minPrize = parseFloat(value);
        return parseFloat(value);
    }
}
function getxzV() {
    const inputNumber = document.getElementById('xzV').value;
    const num = parseInt(inputNumber, 10);
    return isNaN(num) ? 0 : num;
}
function getdhhV() {
    return document.getElementById('dhhV').value;
}
function getffV() {
    const inputNumber = document.getElementById('ffV');
    const value = inputNumber.value.trim();
    if (value === '') {
        return 0;
    } else {
        return parseFloat(value);
    }
}
function clickt3_1(event) {
    clicktbox();
    if (event.keyCode === 13) {
        hideInputBox();
        hideBox3();
    }
}
function toggleBox3() {
    const inputBox = document.getElementById('inputBox');
    const selectedOptions = getCheckboxStatus('#tbox1 input');
    const inputbox3 = document.getElementById('tbox3');
    if (selectedOptions.includes('人气红包')) {
        const currentDisplay = inputBox.style.display;
        if (currentDisplay === 'none') {
            inputBox.style.display = 'inline-block';
        } else {
            inputBox.style.display = 'none';
        }
    } else {
        inputBox.style.display = 'none';
    }
    if (selectedOptions.includes('天选时刻')) {
        const currentDisplay2 = inputbox3.style.display;
        if (currentDisplay2 === 'none') {
            inputbox3.style.display = 'inline-block';
        } else {
            inputbox3.style.display = 'none';
            inputBox.style.display = 'none';
        }
    } else {
        inputbox3.style.display = 'none';
    }
}
function hideInputBox() {
    const inputBox = document.getElementById('inputBox');
    inputBox.style.display = 'none';
}
function hideBox3() {
    const inputBox = document.getElementById('tbox3');
    inputBox.style.display = 'none';
}
function hideBox6() {
    const inputBox = document.getElementById('tbox6');
    inputBox.style.display = 'none';
}


function clickt6() {
    toggleBox6();
    clicktbox();
}

function toggleBox6(){
    const inputBox = document.getElementById('inputBox');
    const selectedOptions = getCheckboxStatus('#tbox1 input');
    const inputbox6 = document.getElementById('tbox6');
    if (selectedOptions.includes('天选时刻')) {
        const currentDisplay2 = inputbox6.style.display;
        if (currentDisplay2 === 'none') {
            inputbox6.style.display = 'inline-block';
        } else {
            inputbox6.style.display = 'none';
            inputBox.style.display = 'none';
        }
    } else {
        inputbox6.style.display = 'none';
    }


}

function clicktbox6(){
    const xz = document.getElementById('xz');
    const dhh = document.getElementById('dhh');
    const ff = document.getElementById('ff');
    const selectedOptions6 = getCheckboxStatus('#tbox6 input');
    if (selectedOptions6.includes('2')) {
        xz.style.display = 'inline-block';
    }else{
        xz.style.display = 'none';
    }
    if (selectedOptions6.includes('3')) {
        dhh.style.display = 'inline-block';
    }else{
        dhh.style.display = 'none';
    }
    if (selectedOptions6.includes('ff')) {
        ff.style.display = 'inline-block';
    }else{
        ff.style.display = 'none';
    }

    const t6 = document.getElementById('t6');
    const container = document.getElementById('tbox6');
    const checkboxes = container.querySelectorAll('input[type="checkbox"]');
    const xzV = document.getElementById('xzV').value;
    const dhhV = document.getElementById('dhhV').value;
    const ffV = document.getElementById('ffV').value;
    let allChecked = true;
    for (const checkbox of checkboxes) {
        if (!checkbox.checked) {
            allChecked = false;
            break;
        }
    }
    if (xzV!=20||dhhV!=1||ffV!=99999){
        allChecked = false;
    }
    if (allChecked) {
        t6.textContent = '';
    } else {
        t6.textContent = '*';
    }

}

function isShow(data){
    let show = true;
    const selectedOptions = getCheckboxStatus('#tbox1 input');
    const firstColumnValue = raffleTypeMapping[data.raffle_type] || '未知类型';
    if (firstColumnValue === '人气红包') {
        const minPrize = getValueFromInputBox();
        const prize = data.total_price / 1e3;
        if (prize < minPrize) {
            show = false;
        }
    }
    const selectedOptions2 = getCheckboxStatus('#tbox3 input');
    if (firstColumnValue === '天选时刻') {
        if (data.award_type==0&&!selectedOptions2.includes("实物天选")){
            show = false;
        }
        if (data.award_type==1&&!selectedOptions2.includes("礼物天选")){
            show = false;
        }
    }
    if (!selectedOptions.includes(firstColumnValue)) {
        show = false;
    }

    const tbox6 = getCheckboxStatus('#tbox6 input');

    if (data.raffle_type === 'ANCHOR') {
        if (!tbox6.includes(data.require_type.toString())){
                //console.log('X 1')
                show = false;
        }else if (data.require_type === 2) {
            console.log(getxzV() ,'?2', data.require_value);
            if (getxzV() < data.require_value){
                //console.log('X 2')
                show = false;
            }
            
        } else if (data.require_type === 3) {
            console.log(getdhhV() ,'?3', data.require_value);
            if (getdhhV() > data.require_value){
                //console.log('X 3')
                show = false;
            }
        }
        console.log(getffV() ,'?4', data.gift_price);

        if ((!tbox6.includes('ff')&&data.gift_price!=0) || (tbox6.includes('ff') &&getffV() < data.gift_price/1e3)){
                //console.log('X 4')
            show = false;
        }
    }
    return show;
}

function clickt6_1(event) {
    clicktbox();
    if (event.keyCode === 13) {
        const inputbox6 = document.getElementById('tbox6');
        inputbox6.style.display = 'none';
        //console.log('勋章等级:',getxzV());
        //console.log('大航海等级:',getdhhV());
        //console.log('付费:',getffV());
    }
}
        </script>
    </body>
</html>
        
